program RenderToTexture;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  SampleCommon,
  DIrr in '..\..\DSource\DIrr.pas',
  DIrr.GUI in '..\..\DSource\DIrr.GUI.pas',
  DIrr.Color in '..\..\DSource\DIrr.Color.pas',
  DIrr.Rect in '..\..\DSource\DIrr.Rect.pas',
  DIrr.Event in '..\..\DSource\DIrr.Event.pas',
  DIrr.Vector2D in '..\..\DSource\DIrr.Vector2D.pas',
  DIrr.Vector3D in '..\..\DSource\DIrr.Vector3D.pas',
  DIrr.Video in '..\..\DSource\DIrr.Video.pas',
  DIrr.Base in '..\..\DSource\DIrr.Base.pas',
  DIrr.Types in '..\..\DSource\DIrr.Types.pas',
  DIrr.Scene in '..\..\DSource\DIrr.Scene.pas',
  DIrr.Structs in '..\..\DSource\DIrr.Structs.pas',
  DIrr.Aabbox3D in '..\..\DSource\DIrr.Aabbox3D.pas',
  DIrr.Matrix4 in '..\..\DSource\DIrr.Matrix4.pas',
  DIrr.Texture in '..\..\DSource\DIrr.Texture.pas',
  DIrr.Collections in '..\..\DSource\DIrr.Collections.pas',
  DIrr.Dimension2d in '..\..\DSource\DIrr.Dimension2d.pas',
  DIrr.Consts in '..\..\DSource\DIrr.Consts.pas';

var
  Driver: TVideoDriver;
  Smgr: TSceneManager;
  Env: TGUIEnvironment;
  Device: TIrrlichtDevice;
  DriverType: E_DRIVER_TYPE;
  Fairy: TAnimatedMeshSceneNode;
  MaterialPtr: PMaterial;
  Test: TSceneNode;
  Anim: TSceneNodeAnimator;
  rt: TTexture;
  FixedCam: TCameraSceneNode;
  Skin: TGUISkin;
  Font: TGUIFont;
  Text: TGUIStaticText;
  FPSCamera: TCameraSceneNode;
  LastFPS, FPS: Integer;
  Str: String;
begin
  try
    { TODO -oUser -cConsole Main : Insert code here }
    DriverType := DriverChoiceConsole;
    if DriverType = EDT_COUNT then
    begin
      ExitCode := 1;
      Exit;
    end;

    // create device and exit if creation failed
    Device := createDevice(DriverType, [640, 480], 16, False, False);
    if Device = nil then
    begin
      ExitCode := 1;   // could not create selected driver.
      Exit;
    end;

	  Driver := Device.GetVideoDriver;
    Smgr := Device.GetSceneManager;
	  Env := Device.GetGUIEnvironment;

    (*
    Now, we load an animated mesh to be displayed. As in most examples,
    we'll take the fairy md2 model. The difference here: We set the
    shininess of the model to a value other than 0 which is the default
    value. This enables specular highlights on the model if dynamic
    lighting is on. The value influences the size of the highlights.
    *)

    // load and display animated fairy mesh

    Fairy := Smgr.AddAnimatedMeshSceneNode(Smgr.GetMesh('..\..\media\faerie.md2'));

    if Assigned(Fairy) then
    begin
      Fairy.SetMaterialTexture(0, Driver.GetTexture('..\..\media\faerie2.bmp'));  // set diffuse texture
      Fairy.SetMaterialFlag(EMF_LIGHTING, True);                               // enable dynamic lighting
      MaterialPtr := Fairy.GetMaterial(0);
      MaterialPtr^.FShininess := 20;                                           // set size of specular highlights

      Fairy.SetPosition(Vector3DF(-10, 0, -100));
      Fairy.SetMD2Animation(EMAT_STAND);
    end;

    (*
    To make specular highlights appear on the model, we need a dynamic
    light in the scene. We add one directly in vicinity of the model. In
    addition, to make the model not that dark, we set the ambient light to
    gray.
    *)

    // add white light
    Smgr.AddLightSceneNode(nil, Vector3DF(-15, 5, -105), IrrColorF(1.0, 1.0, 1.0));

    // set ambient light
    Smgr.SetAmbientLight(IrrColorF(0.235, 0.235, 0.235, 0));

    (*
    The next is just some standard stuff: Add a test cube and let it rotate
    to make the scene more interesting. The user defined camera and cursor
    setup is made later on, right before the render loop.
    *)

    // create test cube
    Test := Smgr.AddCubeSceneNode(60);

    // let the cube rotate and set some light settings
    Anim := Smgr.CreateRotationAnimator(Vector3DF(0.3, 0.3, 0));

    Test.SetPosition(Vector3DF(-100, 0, -100));
    Test.SetMaterialFlag(EMF_LIGHTING, False);       // disable dynamic lighting
    //Test.AddAnimator(Anim);
    Anim.Drop;

    // set window caption
    Device.SetWindowCaption('Irrlicht Engine - Render to Texture and Specular Highlights example');

    (*
    To test out the render to texture feature, we need a render target
    texture. These are not like standard textures, but need to be created
    first. To create one, we call IVideoDriver::addRenderTargetTexture()
    and specify the size of the texture. Please don't use sizes bigger than
    the frame buffer for this, because the render target shares the zbuffer
    with the frame buffer.
    Because we want to render the scene not from the user camera into the
    texture, we add another fixed camera to the scene. But before we do all
    this, we check if the current running driver is able to render to
    textures. If it is not, we simply display a warning text.
    *)

    // create render target
    rt := nil;
    FixedCam := nil;

    if Driver.QueryFeature(EVDF_RENDER_TO_TARGET) then
    begin
      rt := Driver.AddRenderTargetTexture(Dimension2DU(256, 256), 'RTT1');
      Test.SetMaterialTexture(0, rt);  // set material of cube to render target

      // add fixed camera
      FixedCam := Smgr.AddCameraSceneNode(nil, Vector3DF(10, 10, -80), Vector3DF(-10, 10, -100));
    end
    else
    begin
      // create problem text
      Skin := Env.GetSkin;
      Font := Env.GetFont('..\..\media\fonthaettenschweiler.bmp');
      if Assigned(Font) then
        Skin.SetFont(Font);

      Text := Env.AddStaticText
              (
                'Your hardware or this renderer is not able to use the ' +
                  'render to texture feature. RTT Disabled.',
                IrrRect(150, 20, 470, 60)
              );

      Text.SetOverrideColor(IrrColor(100, 255, 255, 255));
    end;

    // add fps camera
    FPSCamera := Smgr.AddCameraSceneNodeFPS();
    FPSCamera.SetPosition(Vector3DF(-50, 50, -150));

    // disable mouse cursor
    Device.GetCursorControl.SetVisible(False);

    (*
    Nearly finished. Now we need to draw everything. Every frame, we draw
    the scene twice. Once from the fixed camera into the render target
    texture and once as usual. When rendering into the render target, we
    need to disable the visibility of the test cube, because it has the
    render target texture applied to it. That's it, wasn't too complicated
    I hope. :)
    *)

    LastFPS := -1;

    while (Device.Run and Assigned(Driver)) do
    begin
      if Device.IsWindowActive then
      begin
        Driver.BeginScene(True, True, IrrColor(0, 200, 200, 200));

        if Assigned(rt) then
        begin
          // draw scene into render target

          // set render target texture
          Driver.SetRenderTarget(rt, True, True, IrrColor(0, 0, 255, 0));

          // make cube invisible and set fixed camera as active camera
          Test.SetVisible(False);
          Smgr.SetActiveCamera(FixedCam);

          // draw whole scene into render buffer
          Smgr.DrawAll;

          // set back old render target
          // The buffer might have been distorted, so clear it
          Driver.SetRenderTarget(nil, True, True, 0);

          // make the cube visible and set the user controlled camera as active one
          Test.SetVisible(True);
          Smgr.SetActiveCamera(FPSCamera);
        end;

        // draw scene normally
        Smgr.DrawAll;
        Env.DrawAll;

        Driver.EndScene;

        // display frames per second in window title
        FPS := Driver.GetFPS;
        if LastFPS <> Driver.GetFPS then
        begin
          Str := 'Irrlicht Engine - Render to Texture and Specular Highlights example';
          Str := Str + '] FPS:' + IntToStr(FPS);
          Str := Str + ' Height: ';

          Device.SetWindowCaption(PChar(Str));
          LastFPS := FPS;
        end;
      end;
    end;

    Device.Drop;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
